<?php
	
	/**
	 * Verifies bootstrapper execution to ensure file
	 * necessities, and disabling direct access
	 */
	defined('ENGINE') or exit;
	
	/**
	 * Session data registry and handler;  Manages standard and persistent
	 * $_SESSION data, and keeps a localized cache of all session data.
	 */
	final class Sessions
	{
		/**
		 * Private instance of engine registry
		 */
		protected $engine;
		
		/**
		 * Private cached sessions available in the
		 * current users visit.
		 */
		private	$sessions				= array();
		
		/**
		 * An array of which sessions are persistent
		 * from the $sessions array
		 */
		private $sessions_persistent	= array();
		
		/**
		 * Number of hours until a session should expire
		 */
		public $cache_expire			= 168;
		
		/**
		 * Constructor, initialize session data and
		 * extract any persistent connections
		 */
		public function __construct()
		{
			$this->engine = Engine::init();
			
			/**
			 * Some servers have the `session.auto_start`
			 * .ini settings to On.  Although this is not
			 * recommended, there's no sense in repeating
			 * the session_start()
			 */
			if(!ini_get('session.auto_start'))
			{
				session_start();
			}
			
			/**
			 * Caches user data
			 */
			$this->ip_address		= $this->engine->db->escape(ip_address());
			$this->http_user_agent	= $this->engine->db->escape(getenv('HTTP_USER_AGENT'));
			$this->timestamp		= date('Y-m-d H:i:s');
			
			/**
			 * Ensure we're recieving a valid ip address
			 * rather than some form of spoof
			 */
			if(!is_valid_ip($this->ip_address))
			{
				throw new Engine_Basic_Exception('The IP Address <code>%s</code> provided user side is not considered a valid IP Address', $this->ip_address);
			}
			
			/**
			 * Caches all $_SESSION variables into the
			 * cache array
			 */
			foreach($_SESSION as $key => $value)
			{
				$this->sessions[$key] = $value;
			}
			
			/**
			 * SELECT all persistent connections in the
			 * database for the users current settings
			 */
			$query = $this->engine->db->query("SELECT * FROM `" . PREFIX . "sessions` WHERE `ip_address` = '" . $this->ip_address . "' AND `http_user_agent` = '" . $this->http_user_agent . "'");
			
			if($query->num_rows())
			{
				/**
				 * Update any persistent connections timestamp
				 * for the current ip and user agent
				 */
				$this->engine->db->query("UPDATE `" . PREFIX . "sessions` SET `timestamp` = '" . $this->timestamp . "' WHERE `ip_address` = '" . $this->ip_address . "' AND `http_user_agent` = '" . $this->http_user_agent . "'");
			
				while($session = $query->fetch_object($query))
				{
					$this->sessions[$session->key] = $session->value;
					$this->sessions_persistent[$session->key] = $session->value;
				}
			}
			
			/**
			 * Remove any deprecated persistent sessions
			 */
			$this->engine->db->set_shutdown_query("DELETE FROM `" . PREFIX . "sessions` WHERE `timestamp` <= '" . date('Y-m-d H:i:s', (strtotime($this->timestamp) - ($this->cache_expire * HOUR))) . "'");
		}
		
		/**
		 * Set or Update a $_SESSION variable as well as the
		 * option for that sessions persistence
		 */
		public function set($key, $value, $persistent = false, $array = false)
		{
			if(empty($key))
			{
				return(false);
			}
			
			$key	= (string) $this->engine->db->escape($key);
			$value	= (string) $this->engine->db->escape($value);
			
			if($persistent == true)
			{
				if(array_key_exists($key, $this->sessions_persistent))
				{
					$this->engine->db->query("UPDATE `" . PREFIX . "sessions` SET `value` = '" . $value . "', `timestamp` = '" . $this->timestamp . "' WHERE `ip_address` = '" . $this->ip_address . "' AND `http_user_agent` = '" . $this->http_user_agent . "' AND `key` = '" . $key . "' LIMIT 1");
				}
				else
				{
					$this->engine->db->query("INSERT INTO `" . PREFIX . "sessions` (`ip_address`, `http_user_agent`, `timestamp`, `key`, `value`) VALUES ('" . $this->ip_address . "', '" . $this->http_user_agent . "', '" . $this->timestamp . "', '" . $key . "', '" . $value . "')");
				}
				
				$this->sessions_persistent[$key] = $value;
			}
			
			if($array)
			{
				$this->sessions[$key][] = $value;
				return($_SESSION[$key][] = $value);
			}
			else
			{
				$this->sessions[$key] = $value;
				return($_SESSION[$key] = $value);
			}
		}
		
		/**
		 * Returns the value of a session set in the local
		 * cache
		 */
		public function get($key)
		{
			if(array_key_exists($key, $this->sessions))
			{
				return($this->sessions[$key]);
			}
			else if(array_key_exists($key, $_SESSION))
			{
				return($this->set($key, $_SESSION[$key], false));
			}
			
			return(false);
		}
		
		/**
		 * Short function for Array sessions
		 */
		public function append($key, $value)
		{
			$this->set($key, $value, false, true);
		}
		
		/**
		 * Permanently remove a session (from persistence and
		 * temporary)
		 */
		public function destroy($key = NULL)
		{
			if(is_null($key))
			{
				return;
			}
			
			if(array_key_exists($key, $this->sessions_persistent))
			{
				$this->engine->db->query("DELETE FROM `" . PREFIX . "sessions` WHERE `key` = '" . $this->engine->db->escape($key) . "' AND `ip_address` = '" . $this->ip_address . "' AND `http_user_agent` = '" . $this->http_user_agent . "' LIMIT 1");
			}
			
			unset($this->sessions[$key], $this->sessions_persistent[$key], $_SESSION[$key]);
			
			return(true);
		}
	}

?>